package io.gitee.h25094152.copy;


import io.gitee.h25094152.copy.annotation.CopyFiledName;
import org.apache.commons.lang3.ObjectUtils;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class BeanUtil {

    /**
     * @param source
     * @param target
     * @param <T>
     * @return
     */
    public static <T> T copyPropertiesIgnoreCase(Object source, Object target) {
        return copyPropertiesIgnoreCase(source, target, false);
    }

    /**
     * 大小写可以忽略
     * 下划线 _ 被忽略
     * NULL值和空字符串不会覆盖新值
     *
     * @param source
     * @param target
     * @param isNullBool 1.true 不覆盖已有值 , 2.false 覆盖所有
     * @param <T>
     * @return
     */
    public static <T> T copyPropertiesIgnoreCase(Object source, Object target, Boolean isNullBool) {
        Map<String, Field> sourceMap = CacheFieldMap.getFieldMap(source.getClass());
        CacheFieldMap.getFieldMap(target.getClass()).values().forEach((it) -> {
            it.setAccessible(true);

            Field field = sourceMap.get(it.getName().toLowerCase().replace("_", ""));

            if (field != null) {

                field.setAccessible(true);
                try {
                    //忽略null和空字符串
                    //if (field.get(source) != null && StringUtils.isBlank(field.get(source).toString())){
                    if (field.get(source) != null) {

                        // 判断是否复盖
                        if (!isNullBool) {
                            if (ObjectUtils.isEmpty(it.get(target))) {
                                if (it.getType().equals(field.getType())) {
                                    it.set(target, field.get(source));
                                }
                            }
                        } else {
                            if (it.getType().equals(field.getType())) {
                                it.set(target, field.get(source));
                            }
                        }
                    }


                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }


            }
        });
        return (T) target;
    }

    /**
     * 忽略大小写 并对注解字段进行换名
     *
     * @param source
     * @param target
     * @param <T>
     * @return
     */
    public static <T> T copyPropertiesAndAnnotationIgnoreCase(Object source, Object target) {
        return copyPropertiesAndAnnotationIgnoreCase(source, target, false);
    }

    public static <T> T copyPropertiesAndAnnotationIgnoreCase(Object source, Object target, Boolean isNullBool) {
        Map<String, Field> sourceMap = CacheFieldAndAnnotationMap.getFieldMap(source.getClass());
        CacheFieldMap.getFieldMap(target.getClass()).values().forEach((it) -> {
            it.setAccessible(true);
            String targetName = it.getName().toLowerCase().replace("_", "");
            Field field = sourceMap.get(targetName);

            if (field != null) {
                field.setAccessible(true);

                try {
                    //忽略null和空字符串
                    //if (field.get(source) != null && StringUtils.isBlank(field.get(source).toString())){
                    if (field.get(source) != null) {

                        // 判断是否复盖
                        if (!isNullBool) {
                            if (ObjectUtils.isEmpty(it.get(target))) {
                                if (it.getType().equals(field.getType())) {
                                    it.set(target, field.get(source));
                                }
                            }
                        } else {
                            if (it.getType().equals(field.getType())) {
                                it.set(target, field.get(source));
                            }
                        }
                    }

                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }


            }
        });
        //System.out.println(target.toString());
        return (T) target;
    }

    private static class CacheFieldMap {
        private static Map<String, Map<String, Field>> cacheMap = new HashMap<>();

        private static Map<String, Field> getFieldMap(Class clazz) {
            Map<String, Field> result = cacheMap.get(clazz.getName());
            if (result == null) {
                synchronized (CacheFieldMap.class) {
                    if (result == null) {
                        Map<String, Field> fieldMap = new HashMap<>();
                        for (Field field : clazz.getDeclaredFields()) {
                            fieldMap.put(field.getName().toLowerCase().replace("_", ""), field);
                        }
                        cacheMap.put(clazz.getName(), fieldMap);
                        result = cacheMap.get(clazz.getName());
                    }
                }
            }
            return result;
        }
    }


    private static class CacheFieldAndAnnotationMap {
        private static Map<String, Map<String, Field>> cacheMap = new HashMap<>();

        private static Map<String, Field> getFieldMap(Class clazz) {
            Map<String, Field> result = cacheMap.get(clazz.getName());
            if (result == null) {
                synchronized (CacheFieldMap.class) {
                    if (result == null) {
                        Map<String, Field> fieldMap = new HashMap<>();
                        for (Field field : clazz.getDeclaredFields()) {
                            if (ObjectUtils.isNotEmpty(field.getAnnotation(CopyFiledName.class))) {
                                CopyFiledName annotation = field.getAnnotation(CopyFiledName.class);
                                String value = annotation.value();
                                if (ObjectUtils.isNotEmpty(annotation.name())) {
                                    value = annotation.name();
                                }
                                fieldMap.put(value.toLowerCase().replace("_", ""), field);
                            } else {
                                fieldMap.put(field.getName().toLowerCase().replace("_", ""), field);
                            }
                        }
                        cacheMap.put(clazz.getName(), fieldMap);
                        result = cacheMap.get(clazz.getName());
                    }
                }
            }
            return result;
        }
    }


}